package com.supor.aiot.home.helper;

import android.content.Context;
import android.os.AsyncTask;

import com.android.baseconfig.common.utils.Logc;
import com.android.baseconfig.common.utils.RxTimerUtil;
import com.android.baseconfig.common.utils.Util;
import com.supor.aiot.common.app.AppAgent;
import com.supor.aiot.common.app.Constants;
import com.supor.nfc.lib.utils.HexUtil;
import com.xbh.wificonfiglib.IWifiConfigLibResult;
import com.xbh.wificonfiglib.IWifiConfigLibTask;
import com.xbh.wificonfiglib.WifiConfigLibTaskByTCPIP;
import com.xbh.wificonfiglib.util.ByteUtil;

import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.List;

import androidx.annotation.NonNull;

/**
 * ---------------------------------------------------------------- <br>
 * Copyright (C) 2014-2020, by het, Shenzhen, All rights reserved.  <br>
 * ---------------------------------------------------------------- <br>
 * <p>
 * 描述: 封装朗国提供的AP配网 <br>
 * 作者: lei <br>
 * 日期: 2020/12/26 <br>
 */
public class WifiConfigHelper {
    private static final String TAG = "WifiConfig";
    private static volatile WifiConfigHelper instance;
    protected EsptouchAsyncTask4 mTask;
    private ConfigListener configListener;
    private boolean configSuccess = false;
    private int timeout = 30000;

    public static WifiConfigHelper getInstance() {
        if (instance == null) {
            instance = new WifiConfigHelper();
        }
        return instance;
    }

    private WifiConfigHelper() {
    }

    public void setConfigListener(ConfigListener configListener) {
        this.configListener = configListener;
    }

    public void startConfig(String ssid, String bssid, String password) {
        configSuccess = false;
        executeEsptouch(ssid, bssid, password);
    }

    public void setConfigSuccess(boolean configSuccess) {
        this.configSuccess = configSuccess;
    }

    public boolean isConfigSuccess() {
        return configSuccess;
    }

    public void startConfig(String ssid, String bssid, String password, int timeout) {
        this.timeout = timeout;
        executeEsptouch(ssid, bssid, password);
    }

    public void executeEsptouch(String ssidStr, String bssidStr, String passwordStr) {
        Logc.i("executeEsptouch： ssidStr= " + ssidStr + ", bssidStr= " + bssidStr);
        byte[] desSsid;
        byte[] bssid;
        boolean ssidWithZh  = false;
        if (Util.hasChineseChar(ssidStr)) {
            try {
                ssidStr = new String(ssidStr.getBytes("GBK"), StandardCharsets.ISO_8859_1);
                Logc.i("executeEsptouch：chinese ssidStr= " + HexUtil.str2HexStr(ssidStr));
            } catch (UnsupportedEncodingException e) {
                Logc.e("UnsupportedEncodingException: GBK");
                e.printStackTrace();
            }
            desSsid = HexUtil.getBytes(ssidStr);
            ssidWithZh = true;
        } else {
            desSsid = ByteUtil.getBytesByString(ssidStr);
        }
        bssid = HexUtil.decodeHex(bssidStr);
        byte[] password = ByteUtil.getBytesByString(passwordStr);
        byte[] deviceCount = "1".getBytes();
        byte[] broadcast = {(byte) 0};

        toExecuteTask(desSsid, bssid, password, deviceCount, broadcast, ssidWithZh);
        startTimer();
    }

    private void startTimer() {
        RxTimerUtil.timer(timeout, number -> {
            if (configListener != null) {
                configListener.onConfig(Code.CONFIG_DEVICE_CONFIG_TIMEOUT, null);
            }
        });
    }

    private void stopTimer() {
        RxTimerUtil.cancel();
    }

    public void stopConfig() {
        stopTimer();
        destroy();
    }

    protected void toExecuteTask(byte[] desSsid, byte[] bssid, byte[] password,
                                 byte[] deviceCount, byte[] broadcast, boolean ssidWithZh) {
        if (mTask != null) {
            mTask.cancelEsptouch();
        }
        mTask = new EsptouchAsyncTask4(this.configListener);
        mTask.setSsidWithZh(ssidWithZh);
        mTask.execute(desSsid, bssid, password, deviceCount, broadcast, desSsid);
    }

    protected @NonNull
    IWifiConfigLibTask createConfigTask(byte[] apSsid, byte[] apBssid, byte[] apPassword,
                                        Context context, boolean ssidWithZh) {
        return new WifiConfigLibTaskByTCPIP(apSsid, apBssid, apPassword, ssidWithZh,
                Constants.SUPOR_AP_IP, Constants.SUPOR_AP_PORT, context);
        // return new WifiConfigLibTask(apSsid, new byte[6], apPassword, context);
    }

    protected class EsptouchAsyncTask4 extends AsyncTask<byte[], IWifiConfigLibResult,
            List<IWifiConfigLibResult>> {
        private ConfigListener configListener;

        private final Object mLock = new Object();
        private IWifiConfigLibTask mEsptouchTask;
        private boolean ssidWithZh;

        EsptouchAsyncTask4() {
        }

        EsptouchAsyncTask4(ConfigListener configListener) {
            this.configListener = configListener;
        }

        void cancelEsptouch() {
            cancel(true);
            if (mEsptouchTask != null) {
                mEsptouchTask.interrupt();
            }
            configListener = null;
        }

        @Override
        protected void onPreExecute() {
        }

        @Override
        protected void onProgressUpdate(IWifiConfigLibResult... values) {
            IWifiConfigLibResult result = values[0];
            Logc.i(TAG, "EspTouchResult: " + result);
        }

        @Override
        protected List<IWifiConfigLibResult> doInBackground(byte[]... params) {
            int taskResultCount;
            synchronized (mLock) {
                byte[] apSsid = params[0];
                byte[] apBssid = params[1];
                byte[] apPassword = params[2];
                byte[] deviceCountData = params[3];
                byte[] broadcastData = params[4];
                taskResultCount = deviceCountData.length == 0 ? -1 :
                        Integer.parseInt(new String(deviceCountData));
                //新建wifi配置配置任务，传入AP名称和密码（bssid目前没有用到可以不传）
                mEsptouchTask = createConfigTask(apSsid, apBssid, apPassword,
                        AppAgent.getApp(), ssidWithZh);
                /*//设置包发送形式：true：广播；false：多路发送，这里默认为true
                mEsptouchTask.setPackageBroadcast(broadcastData[0] == 1);
                //设备连接回调接口，单ap不需要设置
                mEsptouchTask.setEsptouchListener(this::publishProgress);*/
            }
            //开始接受模块端结果，
            return mEsptouchTask.executeForResults(taskResultCount);
        }

        @Override
        protected void onPostExecute(List<IWifiConfigLibResult> result) {
            if (result == null || result.isEmpty()) {
                Logc.e("onPostExecute: Create WifiConfig task failed");
                return;
            }

            // check whether the task is cancelled and no results received
            IWifiConfigLibResult firstResult = result.get(0);
            if (firstResult.isCancelled()) {
                return;
            }
            // the task received some results including cancelled while
            // executing before receiving enough results

            if (!firstResult.isSuc()) {
                Logc.e("onPostExecute: config failed");
                if (configListener != null) {
                    configListener.onConfig(Code.CONFIG_DEVICE_CONFIG_SEND_FAILED, null);
                }
                return;
            }

            if (configListener != null) {
                configListener.onConfig(Code.CONFIG_SUCCESS, result.get(0).getMacAddr());
            }
        }

        public boolean isSsidWithZh() {
            return ssidWithZh;
        }

        public void setSsidWithZh(boolean ssidWithZh) {
            this.ssidWithZh = ssidWithZh;
        }
    }

    public interface ConfigListener {
        void onConfig(Code code, String mac);
    }

    public enum Code {
        CONFIG_SUCCESS,
        CONFIG_DEVICE_CONFIG_SEND_FAILED,
        CONFIG_DEVICE_CONFIG_IS_RUNNING,
        CONFIG_DEVICE_CONFIG_TIMEOUT,
        CONFIG_PHONE_NOT_CONNECT_TO_SOFTAP_SSID,
        CONFIG_ONBOARDING_STOPPED,
        CONFIG_DEVICE_CONFIG_SSID_NOT_MATCHED;

        private Code() {
        }
    }


    public void destroy() {
        if (mTask != null) {
            mTask.cancelEsptouch();
            mTask = null;
        }
    }
}
